/**
 * 通用uni-app网络请求
 * 基于 Promise 对象实现更简单的 request 使用方式，支持请求和响应拦截
 */
import { getHost } from '@u/url';
import { setAuthorization, getAuthorization } from '@/router/auth.js';
import { apiBaseURL } from '@/config/index.js';

// 刷新token
import { authLogin } from '@/api/customApi.js';

// 请求错误自定义
let errorCode = {
    403: '当前操作没有权限',
    404: '访问资源不存在',
    default: '系统未知错误,请反馈给管理员',
};

// 请求存储
let axiosPromiseArr = [];

// loading白名单
let loadWhite = [];
/**
 * 判断是否为JSON格式
 * @param {*} str
 * @returns
 */
function isJSON(str) {
    if (typeof str == 'string') {
        try {
            JSON.parse(str);
            return true;
        } catch (e) {
            return false;
        }
    }
}

/**
 * 创建缓存key, 由请求url、类型、参数、发送数据构成的标识符
 * @param {string} url 请求url
 * @param {string} type 请求类型
 * @param {object} data 请求数据
 * @return {string}
 */
function createKey({ url, method, data = {} }) {
    return encodeURIComponent([url, method, isJSON(data) ? data : JSON.stringify(data)].join(','));
}

let isRefreshing = false,
    needRetryRequest = [];

let config = {
        header: {
            'Content-Type': 'application/json;charset=UTF-8',
        },
        data: {},
        method: 'GET',
        // 如果设为 json，会尝试对返回的数据做一次 JSON.parse
        dataType: 'json',
    },
    // 请求拦截器
    interceptor = {
        /**
         * 请求前置拦截器（参数处理）
         */
        request: (config) => {
            // 必须要传入url
            if (!config.url) throw new Error('ajax url is required!');

            if (!getHost(config.url)) config.url = apiBaseURL + config.url;

            // 是否需要设置 token
            const isToken = (config.header || {}).isToken === false,
                token = getAuthorization();
            if (!isToken) {
                if (token) {
                    const userInfo = uni.getStorageSync('userInfo');
                    const {
                        tenantList: [{ clientId = '', tenantId = '' }],
                    } = userInfo;
                    config.header['Authorization'] = 'Bearer ' + token; // 让每个请求携带自定义token
                    config.header['gc-authentication'] = token;
                    config.header['client-code'] = clientId;
                    config.header['tenant-code'] = tenantId;
                } else {
                    config.NoToken = true;
                }
            }
            delete config.header.isToken;

            if (!config.NoToken) {
                // 创建全局loading，排除不需要loading的接口
                if (axiosPromiseArr.length === 0 && !loadWhite.includes(config.url)) uni.showLoading({ title: '加载中...' });

                const key = createKey(config);
                axiosPromiseArr.push(key);
            }

            config.sslVerify = false;
            return config;
        },
        /**
         * 请求后置拦截器（数据处理）
         */
        response: (res, resolve, reject, config) => {
            // 请求状态，未设置则默认为200
            let code = res.statusCode || res.data.code || 200;
            // 获取错误信息
            const msg = errorCode[code] || res.data.msg || errorCode['default'];
            if ([401, '401'].includes(code)) {
                if (uni.getStorageSync('userName') && uni.getStorageSync('password') && !isRefreshing && getAuthorization()) {
                    isRefreshing = true;
                    return authLogin({
                        userName: uni.getStorageSync('userName'),
                        password: uni.getStorageSync('password'),
                        clientType: 'phone',
                        phoneId: '',
                        privacyVer: '15',
                        locale: 'zh-CN',
                    })
                        .then((res) => {
                            const { accessToken, userInfo } = res;
                            setAuthorization(accessToken);
                            uni.setStorageSync('userInfo', userInfo);

                            // token 刷新后将数组的方法重新执行
                            needRetryRequest.forEach((cb) => cb(accessToken));
                            needRetryRequest = []; // 重新请求完清空

                            config.header['Authorization'] = 'Bearer ' + accessToken; // 让每个请求携带自定义token
                            config.header['gc-authentication'] = accessToken;

                            uni.request(config);
                            // uni.reLaunch({
                            // 	url: `/${getCurrentPages().shift().route}`
                            // })
                        })
                        .catch(() => {
                            uni.reLaunch({
                                url: '/pages/login/login',
                            });
                            setTimeout(() => {
                                uni.showToast({
                                    title: '登录失败',
                                    icon: 'error',
                                });
                                reject(res.data);
                            });
                        })
                        .finally(() => {
                            isRefreshing = false;
                        });
                } else if (isRefreshing) {
                    // 返回未执行 resolve 的 Promise
                    new Promise((resolve) => {
                        // 用函数形式将 resolve 存入，等待刷新后再执行
                        needRetryRequest.push((token) => {
                            config.header['Authorization'] = 'Bearer ' + token; // 让每个请求携带自定义token
                            config.header['gc-authentication'] = token;
                            resolve(uni.request(config));
                        });
                    });
                } else {
                    if (!isRefreshing) {
                        uni.reLaunch({
                            url: '/pages/login/login',
                        });
                        setTimeout(() => {
                            uni.showToast({
                                title: '身份证已过期，请重新登录',
                                icon: 'error',
                            });
                            reject(res.data);
                        });
                    }
                }
            } else if (!(code == 200 || code == 1)) {
                setTimeout(() => {
                    uni.showToast({
                        title: msg,
                        icon: 'error',
                    });
                }, 0);
                reject(res.data);
            } else {
                resolve(res.data);
            }
        },
    };

/**
 * 请求方法
 */
const apiFn = function (options = {}) {
    // 基于 Promise 的网络请求
    return new Promise((resolve, reject) => {
        /**
         * 请求前置拦截器
         */
        let _config = interceptor.request({
            ...config,
            ...options,
        });
        // 请求成功
        _config.success = (res) => {
            interceptor.response(res, resolve, reject, _config);
        };
        // 请求失败
        _config.fail = (error) => {
            let { errMsg } = error;
            if (errMsg) {
                if (errMsg == 'Network Error') {
                    errMsg = '后端接口连接异常';
                } else if (errMsg.includes('timeout')) {
                    errMsg = '系统接口请求超时';
                } else if (errMsg.includes('Request failed with status code')) {
                    errMsg = '系统接口' + errMsg.substr(errMsg.length - 3) + '异常';
                }
                setTimeout(() => {
                    uni.showToast({
                        title: errMsg,
                        icon: 'error',
                    });
                }, 0);
            }
            reject(error);
        };
        // 接口调用结束的回调函数（调用成功、失败都会执行）
        _config.complete = () => {
            setTimeout(() => {
                axiosPromiseArr.pop();
                // 全部请求结束关闭loading
                if (axiosPromiseArr.length === 0) uni.hideLoading();
            }, 500);
        };
        // 发送请求
        if (!_config.NoToken) {
            delete _config.NoToken;
            return uni.request({
                ..._config,
            });
        }
    });
};

export default apiFn;
